<?php
/**
 * @Notes:【】
 * @User: zwc
 * @Date: 2022-05-04 21:30
 */

namespace App\Service\Task;

use App\Dao\Task\TaskBlacklistDao;
use App\Dao\Task\TaskComplaintDao;
use App\Dao\Task\TaskDao;
use App\Dao\Task\TaskLogDao;
use App\Dao\Task\TaskReceiveDao;
use App\Dao\Task\TaskStepsDao;
use App\Dao\Task\TaskStepsRulesDao;
use App\Dao\Task\TaskTypesDao;
use App\Dao\User\UserDao;
use App\Model\Task\TaskBlacklist;
use App\Model\Task\TaskLog;
use App\Model\Task\TaskReceive;
use App\Model\Task\TaskSteps;
use App\Model\Task\TaskStepsRules;
use App\Service\BaseService;
use Hyperf\DbConnection\Db;
use Hyperf\Di\Annotation\Inject;
use Hyperf\Utils\Collection;

class TaskService extends BaseService
{
    /**
     * @Inject()
     * @var TaskDao
     */
    protected $taskDao;

    /**
     * @Inject()
     * @var TaskLogDao
     */
    protected $taskLogDao;

    /**
     * @Inject()
     * @var UserDao
     */
    protected $userDao;
    /**
     * @Inject()
     * @var TaskStepsDao
     */
    protected $taskStepsDao;

    /**
     * @Inject()
     * @var TaskStepsRulesDao
     */
    protected $taskStepsRuleDao;
    /**
     * @Inject()
     * @var TaskTypesDao
     */
    protected $taskTypesDao;

    /**
     * @Inject()
     * @var TaskReceiveDao
     */
    protected $taskRevicesDao;

    public function add(Collection $data)
    {
        Db::beginTransaction();
        try {
            if ($data->offsetExists('one_price') && $data->offsetExists('stock')) {
                $data->offsetSet('price', bcmul($data->get('one_price'), $data->get('stock'), 2));
            }
            if ($data->offsetExists('stock')) {
                $data->offsetSet('total_stock', $data->get('stock'));
            }

            $task = $this->taskDao->create($data->toArray());
            $taskSteps = collect($data->get('task_steps'));
            $taskSteps->every(function ($step) use ($task) {
                $taskSteps = $task->TaskSteps()->save(new TaskSteps([
                    'title' => $step['title'],
                    'types' => $step['types'],
                ]));
                $rules = collect($step['task_steps_rules']);
                $rules->transform(function ($rule) {
                    if (empty($rule['value'])) {
                        _Exception("请填写{$rule['title']}");
                    }
                    return new TaskStepsRules($rule);
                });
                $taskSteps->TaskStepsRules()->saveMany($rules);
                return true;
            });
            Db::commit();
        } catch (\Exception $e) {
            Db::rollback();
            _Error($e->getMessage());
        }
        return $task;
    }

    public function lists($params)
    {
        $query = $this->taskDao
            ->DaoWhereStatus($params->get('status'))
            ->DaoWhere($params->toArray())
            ->tap(function ($query) use ($params) {
                if ($nickname = $params->get('nickname')) {
                    $query->whereHasIn('User', function ($query) use ($nickname) {
                        $query->where('nickname', 'like', '%' . $nickname . '%');
                    });
                }
                if ($nickname = $params->get('phone')) {
                    $query->whereHasIn('User', function ($query) use ($nickname) {
                        $query->where('phone', 'like', '%' . $nickname . '%');
                    });
                }
                return $query;
            })
            ->with('image')
            ->with(['User', 'TaskTypes']);

        $sort = $params->get('sort', 'id');
        if (is_array($sort)) {
            foreach ($sort as $oneSort) {
                $query->orderByDesc($oneSort);
            }
        }
        $data = $query->orderByDesc('id')->getList();
        $data->setAppends([
            'unFinishNum',
            'create_date',
            'status_format',
            'end_time_format',
            'beans',
        ]);
        return $data;
    }

    public function getTypes()
    {
        $data = $this->taskTypesDao->getList();
        _SUCCESS($data);
    }


    public function edit($task_id, $data)
    {


        Db::beginTransaction();
        try {
            $taskDao = $this->taskDao->where('id', $task_id)->firstOrFail();
            $data->offsetSet('price', bcmul($data->get('one_price'), $data->get('stock'), 2));
            $taskDao->fill($data->toArray());
            $taskDao->save();
            if ($data->offsetExists('task_steps')) {
                $this->updateSteps($task_id, $data->get('task_steps'));
            }
            Db::commit();
        } catch (\Exception $exception) {
            Db::rollback();
            _Error($exception->getMessage());
        }
        return true;
    }

    public function updateSteps($task_id, $task_steps)
    {
        $taskSteps = _Collect($task_steps);
        $ids = $taskSteps->where('id', '>', 0)->pluck('id');
        //删除
        $this->taskStepsDao->where('task_id', $task_id)->where(function ($query) use ($ids) {
            $ids->isNotEmpty() && $query->whereNotIn('id', $ids->toArray());
        })->delete();

        $taskSteps->where('id', 0)->every(function ($step) use ($task_id) {
            $taskSteps = $this->taskStepsDao->create([
                'task_id' => $task_id,
                'title' => $step['title'],
            ]);
            $task_steps_rules = collect($step['task_steps_rules']);
            $task_steps_rules->transform(function ($rule) {
                if (empty($rule['value'])) {
                    _Exception("请填写{$rule['title']}");
                }
                return new TaskStepsRules($rule);
            });
            $taskSteps->TaskStepsRules()->saveMany($task_steps_rules);
            return true;
        });

        $taskSteps->where('id', '>', 0)->every(function ($step) use ($task_id) {
            dump($task_id);
            $taskSteps = $this->taskStepsDao->where('task_id', $task_id)->firstOrError();
            $taskSteps->fill($step);
            $taskSteps->save();
            $task_steps_rules = collect($step['task_steps_rules']);
            $task_steps_rules->every(function ($rule) use ($taskSteps) {
                $TaskStepsRules = $this->taskStepsRuleDao->where('task_steps_id', $rule['task_steps_id'])
                    ->where('id', $rule['id'])->firstOrError();
                $TaskStepsRules->fill($rule);
                $TaskStepsRules->save();
                return true;
            });
            return true;
        });
    }

    public function detail(\App\Tool\Collect $validator)
    {
        $task_id = $validator->get('task_id');
        $task_receive_id = $validator->get('task_receive_id', 0);
        $data = $this->taskDao->DaoWhere($validator->only('task_id')->toArray())
            ->with(['Image', 'User', 'TaskSteps' => function ($query) {
                $query->with('TaskStepsRules');
            }])
            ->first();

        $data->increment('view', 1);
        $data->save();

        if ($task_receive_id) {
            $isReceive = true;
        } else {
            $isReceive = $this->taskRevicesDao->isReceive($validator->getUserId(false), $task_id);
        }

        if ($isReceive) {
            if ($task_receive_id == 0) {
                $task_receive_id = $this->taskRevicesDao->getUnFinishId($validator->getUserId(false), $task_id);
            }

            if ($task_receive_id) {
                $data->receive = $this->taskRevicesDao->getDetailById($task_receive_id);
            }
        }

        $data->isReceive = $isReceive;
        $data->task_receive_id = $task_receive_id;

        $data->finishNum = $this->taskRevicesDao->getFinishedNum($task_id);
        $receiveDetail = _Collect($data->receive->TaskReceiveDetail);
        $data->TaskSteps->transform(function ($TaskStep) use ($receiveDetail, $isReceive, $task_receive_id) {
            $TaskStep->TaskStepsRules->transform(function ($TaskStepsRule) use ($receiveDetail, $isReceive, $task_receive_id) {
                if (in_array($TaskStepsRule->field, ['screenshot']) && $isReceive) {
                    $TaskStepsRule->submit = $receiveDetail
                        ->where('task_steps_rules_id', $TaskStepsRule->id)->where('task_receive_id', $task_receive_id)->first()->value;
                }
                return $TaskStepsRule;
            });
            return $TaskStep;
        });

        $data->statistics = array_merge($this->getTaskStatic($data->user_id), App(TaskReceiveService::class)->taskStatistics($task_id));
//        $data->statistics = App(TaskReceiveService::class)
//            ->taskStatistics($task_id);

        return ($data);
    }

    public function getTaskStatic(int $uid)
    {
        $taskCount = App(TaskDao::class)->where('user_id', $uid)->where('status', '<>', 0)->count();
        $taskOnlineCount = App(TaskDao::class)->where('user_id', $uid)->where('status', 2)->count();
        $passCount = App(TaskReceive::class)
            ->where('user_id', $uid)
            ->where('status', 100)
            ->count();
        $rejectCount = App(TaskReceive::class)
            ->where('user_id', $uid)
            ->where('status', -1)
            ->count();
//        dump($rejectCount,$passCount);
        if (($passCount + $rejectCount) == 0) {
            $rate = 100;
        } else {
            $rate = bcdiv($passCount, $rejectCount + $passCount, 2) * 100;
        }

        return compact('taskCount', 'taskOnlineCount', 'rate');
    }

    public function receive($userId, $taskId)
    {
        $isReceive = $this->taskRevicesDao->isReceive($userId, $taskId);
        if ($isReceive) {
            _Error('已经领取过了');
        }

        $taskDao = $this->taskDao->DaoWhere(['task_id' => $taskId])->first();
        $submit_cycle = $taskDao->submit_cycle;
        $taskDao->stock -= 1;
        $taskDao->save();

        $this->taskRevicesDao->create([
            'task_price' => $taskDao->one_price,
            'tasker_id' => $taskDao->user_id,
            'user_id' => $userId,
            'task_id' => $taskId,
            'cancel_time' => $submit_cycle * 3600 + time()
        ]);

        return true;
    }

    public function getStatis(int $userID)
    {
        $total = $this->taskDao->DaoWhere(['user_id' => $userID])->count();
        $processing = $this->taskDao->DaoWhere(['user_id' => $userID, 'status' => 1])->count();
        return compact('total', 'processing');
    }

    public function changePrice($task_id, $one_price)
    {
        //判断是否支付过了
        $task = $this->taskDao->DaoWhere(['task_id' => $task_id])->firstOrError();
        if ($task->pay_status == 1) {
            _Error('该订单已经支付');
        }
        if ($one_price <= $task->one_price) {
            _Error('金额不能小于￥' . $task->one_price);
        }
        $task->one_price = $one_price;
        $task->price = bcmul($task->one_price, $task->stock, 2);
        $task->save();
        return true;
    }


    public function changeStock($task_id, $stock)
    {
        //判断是否支付过了
        $task = $this->taskDao->DaoWhere(['task_id' => $task_id])->firstOrError();
        if ($task->pay_status == 1) {
            _Error('该订单已经支付');
        }
        if (($stock + $task->stock) < 0) {
            _Error('库存不能小于当前库存');
        }
        $task->increment('stock', $stock);
        $task->increment('total_stock', $stock);

        $task->price = bcmul($task->one_price, $task->stock, 2);
        $task->save();

        return true;
    }

    public function audit(\App\Tool\Collect $data)
    {
        Db::beginTransaction();
        try {
            $task = $this->taskDao->DaoWhere(['task_id' => $data->get('task_id')])->firstOrError();
            if ($task->status !== 1) {
                _Exception('已经审核了');
            }
            $task->fill($data->toArray());
            $task->save();
            Db::commit();
        } catch (\Exception $e) {
            Db::rollBack();
            _Error($e->getMessage());
        }
        return true;
    }

    public function shelf($task_id)
    {
        $task = $this->taskDao->DaoWhere(['task_id' => $task_id])->firstOrError();
        if ($task->status !== -1) {
            _Error('状态不对');
        }
        $task->status = 1;
        return $task->save();
    }

    public function recomment(\App\Tool\Collect $data)
    {
        $task = $this->taskDao->DaoWhere(['task_id' => $data->get('task_id')])->firstOrError();
        if ($task->status !== 2) {
            _Error('禁止推荐');
        }
        $task->fill($data->only('recomment_reason')->toArray() + ['recomment_time' => time()]);
        return $task->save();
    }


    public function cancelRecomment(\App\Tool\Collect $data)
    {
        $task = $this->taskDao->DaoWhere(['task_id' => $data->get('task_id')])->firstOrError();
        $task->recomment_time = 0;
        return $task->save();
    }

    public function top($user_id, $task_id)
    {
        $user = $this->userDao->where('uid', $user_id)->firstOrError();

        $user->top_num -= 1;
        if ($user->top_num < 0) {
            _Error('置顶次数不足');
        }
        Db::beginTransaction();
        try {
            $user->save();
            //记录日志
            $this->taskLogDao->create([
                'user_id' => $user_id,
                'task_id' => $task_id,
                'types' => 'top'
            ]);
            $task = $this->taskDao->DaoWhere(['task_id' => $task_id])->firstOrError();
            $task->top_time = time();

            $task->save();
            Db::commit();
        } catch (\Exception $e) {
            Db::rollBack();
            _Error($e->getMessage());
        }
        return true;
    }

    public function refresh($user_id, $task_id)
    {
        $user = $this->userDao->where('uid', $user_id)->firstOrError();
        $user->refresh_num -= 1;
        if ($user->refresh_num < 0) {
            _Error('置顶次数不足');
        }
        Db::beginTransaction();
        try {
            $user->save();
            //记录日志
            $this->taskLogDao->create([
                'user_id' => $user_id,
                'task_id' => $task_id,
                'types' => 'refresh'
            ]);
            $task = $this->taskDao->DaoWhere(['task_id' => $task_id])->firstOrError();
            $task->refresh_time = time();
            $task->save();
            Db::commit();
        } catch (\Exception $e) {
            Db::rollBack();
            _Error($e->getMessage());
        }
        return true;
    }

    public function settlement(int $task_id, int $user_id)
    {
        Db::beginTransaction();
        try {
            $task = $this->taskDao
                ->where('id', $task_id)
                ->where('user_id', $user_id)
                ->firstOrError();
            if ($task->end_time > time()) {
                _Error('活动还未结束');
            }
            $price = bcmul($task->total_stock, $task->one_price, 2);
            if ($price > 0) {
                $this->userDao->opAccount('now_money', $user_id, $price, 'task_settlement');
            }
            $task->status = 10;
            $task->save();
            Db::commit();
        } catch (\Exception $exception) {
            DB::rollBack();
            _Error($exception->getMessage());
        }
        return true;
    }

    /**
     * @var TaskComplaintDao
     */
    protected $taskComplaintDao;

    public function complaint(mixed $userId, \App\Tool\Collect $params)
    {
        $params->put('user_id', $userId);
        return $this->taskComplaintDao->create($params->toArray());
    }

    public function getStatistics(\App\Tool\Collect $params)
    {
        //审核中
        $auditing = $this->taskDao->getTotal($params->get('user_id'), 1);
        $refusing = $this->taskDao->getTotal($params->get('user_id'), -1);
        $progressing = $this->taskDao->getTotal($params->get('user_id'), 2);
        $settlementing = $this->taskDao->getTotal($params->get('user_id'), 3);
        $stoping = $this->taskDao->getTotal($params->get('user_id'), 10);
        return compact('auditing', 'refusing', 'progressing', 'settlementing', 'stoping');

    }

    public function setFieldStatus(int $id, string $field, int $value)
    {
        return $this->taskDao->setField($id, $field, $value);
    }

    /**
     * @Inject()
     * @var TaskBlacklistDao
     */
    protected $taskBlacklistDao;

    public function black(mixed $user_id, \App\Tool\Collect $params)
    {
        $params->put('user_id', $user_id);
        return $this->taskBlacklistDao->add($params);
    }

}